package util

import (
	"fmt"
	"log"
	"net"
	"strconv"
	"strings"
)

type DBMe interface {
	Put(key []byte, val []byte) error
	Get(key []byte) ([]byte, error)
	Mod(key []byte, val []byte) error
	Del(key []byte) (err error)
	GetTime(key []byte) (val uint32, err error)
}

type ConnList struct {
	Wbuffer []byte
	Wlen    int
	Rbuffer []byte
	Rlen    int
	Net     net.Conn
	DB      DBMe
}

func KvAccept(rbuf []byte, connEntry *ConnList) (any, int) {
	split := strings.Split(string(rbuf), " ")
	split[0] = strings.ToUpper(split[0])
	if len(split) >= 2 {
		split[len(split)-1] = split[len(split)-1][:len(split[len(split)-1])-1] //去掉最后的分号
	}
	switch split[0] {
	case "SET":
		if len(split) != 3 {
			return nil, OPTERROR
		}
		key := split[1]
		val := split[2]
		err := connEntry.DB.Put([]byte(key), []byte(val))
		if err != nil {
			return nil, SETFILED
		}
		return nil, SETSUCCESS
	case "GET":
		if len(split) != 2 {
			return nil, OPTERROR
		}
		key := split[1]
		val, err := connEntry.DB.Get([]byte(key))
		if err != nil {
			return nil, NOFIND
		}
		return string(val), FINDSUCCESS
	case "MOD":
		if len(split) != 3 {
			return nil, OPTERROR
		}
		key := split[1]
		val := split[2]
		err := connEntry.DB.Mod([]byte(key), []byte(val))
		if err == nil {
			return nil, MODSUCCESS
		} else {
			return nil, MODERROR
		}
	case "DEL":
		if len(split) != 2 {
			return nil, OPTERROR
		}
		key := split[1]
		err := connEntry.DB.Del([]byte(key))
		if err != nil {
			return nil, DELERROR
		}
		return nil, DELSUCCESS
	case "TIME":
		if len(split) != 2 {
			return nil, OPTERROR
		}
		key := split[1]
		val, err := connEntry.DB.GetTime([]byte(key))
		if err != nil {
			return nil, NOFIND
		}
		return val, TIMSUCCESS
	}
	return nil, PARSEERROR
}

func HandleConnection(conns *ConnList) {
	handleSingleConnection(conns)
}

func handleSingleConnection(connEntry *ConnList) {
	defer func() {
		err := connEntry.Net.Close()
		if err != nil {
			log.Fatal(err)
		}
	}()
	var err error
	for {
		connEntry.Rlen = 0
		connEntry.Rbuffer = make([]byte, 0)
		for {
			tmpBuffer := make([]byte, 4096)
			n, err := connEntry.Net.Read(tmpBuffer)
			connEntry.Rlen += n
			connEntry.Rbuffer = append(connEntry.Rbuffer, tmpBuffer[:n]...)
			if err != nil {
				fmt.Println(err)
				break
			}
			if string(tmpBuffer[n-1]) == ";" {
				break
			}
		}
		val, state := KvAccept(connEntry.Rbuffer, connEntry)
		switch state {
		case SETSUCCESS:
			_, err = connEntry.Net.Write([]byte("SetSuccess;"))
		case NOFIND:
			_, err = connEntry.Net.Write([]byte("NotFind;"))
		case PARSEERROR:
			_, err = connEntry.Net.Write([]byte("ParseError;"))
		case FINDSUCCESS:
			_, err = connEntry.Net.Write([]byte(val.(string) + ";"))
		case MODSUCCESS:
			_, err = connEntry.Net.Write([]byte("ModSuccess;"))
		case MODERROR:
			_, err = connEntry.Net.Write([]byte("ModError;"))
		case SETFILED:
			_, err = connEntry.Net.Write([]byte("KeyFiled;"))
		case OPTERROR:
			_, err = connEntry.Net.Write([]byte("CmdError;"))
		case DELSUCCESS:
			_, err = connEntry.Net.Write([]byte("DelSuccess;"))
		case DELERROR:
			_, err = connEntry.Net.Write([]byte("DelError;"))
		case TIMSUCCESS:
			_, err = connEntry.Net.Write([]byte(strconv.Itoa(int(val.(uint32))) + ";"))
		default:
			panic("unhandled default case")
		}
		if err != nil {
			fmt.Println("Error writing:", err.Error())
			return
		}
	}
}
